package yui.comn.hub.extension.enums;

import static org.springframework.util.StringUtils.tokenizeToStringArray;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.StringPool;

import lombok.extern.slf4j.Slf4j;
import yui.comn.hub.extension.config.HubExtensionProperties;
import yui.comn.hub.extension.model.CdNmModel;
import yui.comn.hub.extension.utils.PackageHelper;
import yui.comn.hub.model.BaseEnum;
import yui.comn.mybatisx.extension.utils.SerializeUtils;

/**
 * <p>
 * 枚举注册器
 * </p>
 *
 * @author yuyi (1060771195@qq.com)
 */
@Slf4j
@EnableConfigurationProperties(HubExtensionProperties.class)
public class EnumRegistry {

	@Autowired
	private HubExtensionProperties hubExtensionProperties;
	
    private RedisTemplate<String, String> redisTemplate;
    
    public EnumRegistry(RedisTemplate<String, String> redisTemplate) {
    	this.redisTemplate = redisTemplate;
    }
    
    @SuppressWarnings("rawtypes")
    @PostConstruct
    public void register() {
    	String typeEnumsPackage = hubExtensionProperties.getTypeEnumsPackage();
    	
        Set<Class> classes;
        if (typeEnumsPackage.contains(StringPool.STAR) && !typeEnumsPackage.contains(StringPool.COMMA)
            && !typeEnumsPackage.contains(StringPool.SEMICOLON)) {
            classes = PackageHelper.scanTypePackage(typeEnumsPackage);
            if (classes.isEmpty()) {
                log.warn("Can't find class in '[" + typeEnumsPackage + "]' package. Please check your configuration.");
            }
        } else {
            String[] typeEnumsPackageArray = tokenizeToStringArray(typeEnumsPackage,
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
            Assert.notNull(typeEnumsPackageArray, "not find typeEnumsPackage:" + typeEnumsPackage);
            classes = new HashSet<>();
            for (String typePackage : typeEnumsPackageArray) {
                Set<Class> scanTypePackage = PackageHelper.scanTypePackage(typePackage);
                if (scanTypePackage.isEmpty()) {
                    log.warn("Can't find class in '[" + typePackage + "]' package. Please check your configuration.");
                } else {
                    classes.addAll(PackageHelper.scanTypePackage(typePackage));
                }
            }
        }
        if (null != classes && !classes.isEmpty()) {
            for (Class cls : classes) {
                classHandle(cls);
            }
        }
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void classHandle(Class cls) {
        if (!cls.isEnum()) {
            return;
        }
        Class[] interfaces = cls.getInterfaces();
        if (null == interfaces || interfaces.length == 0) {
            return;
        }
        
        boolean flag = false;
        for (Class inter : interfaces) {
            if (inter == BaseEnum.class) {
                flag = true;
                break;
            }
        }
        
        if (!flag) {
            return;
        }
        
        try {
            List<CdNmModel> list = new ArrayList<>();
            Method method = cls.getMethod("values");
            BaseEnum[] ens = (BaseEnum[]) method.invoke(null);
            for (BaseEnum item : ens) { 
                list.add(new CdNmModel(item.cd(), item.nm()));
            }
            
            redisTemplate.execute(new RedisCallback<Boolean>() {
                public Boolean doInRedis(RedisConnection connection)
                        throws DataAccessException {
                    Boolean hSet = connection.hSet(hubExtensionProperties.getRedisPrefix().getBytes(), 
                    		StringUtils.substringAfterLast(cls.getName(), ".").getBytes(), 
                    		SerializeUtils.serialize(list));
                    return hSet;
                }
            });
            
        } catch (Exception e) {
            log.error(cls.getName() + " enum class handle error", e);
        }
    }
    
    
}
